# lllm-janet 
## Lisp's elegance and Assembly's cold-blooded efficiency.  
![the-lllm-logo](./graphics/lllm-logo.png)
> "Lisp is a slow language." --Famous last words

This is the [Janet](https://janet-lang.org/)-flavoured implementation of lllm.

It currently focuses on the [x86_64](https://wl.vern.cc/wiki/X86-64) but it would be trivial to add support for other architectures.

-----


## Introduction
*** Tl;dr: lllm is a family of DSLs for writing Assembly via the Lisp family of programming languages. ***

This is the first -and currently only- Janet lllm implementation\*. Janet is a quite portable and embeddable pseudo-Lisp that is mostly written in standard C99; think of it as Clojure if you don't like the Java ecosystem, or, better, as Lisp with much easier UNIX-/C-y data manipulation.

lllm is not a "compiler" nor is it "compiled" in the standard sense.

It could be said that **current compilers are built "top-down"**, ie. abstractions are first defined, such as arrays, and then bruteforced into fitting the architecture's machine code (or the architecture is built around the compiler, which could promote some amount of language lock-in in the worst cases)

By analogy, **lllm would build itself "bottom-up"**: you begin by defining extremely simple abstractions (such as loops) that directly translate to a list of assembly instructions; then, you begin abstracting those abstractions, raising the level of abstraction higher (print statements, BIOS mode handling, a generic syscall function ...) as necessary, while keeping your code highly flexible and hackable.

Keep in mind lllm *(and lllm-janet)* is still in its infancy; while it seems to work as intended and is a very simple concept in and of itself, it and its libraries are still heavily subject to change.

With that said, you can use it to generate perfectly valid assembly code and even bootloaders.

***(\: There is a systems programming lisp called [Ink](https://github.com/whily/yalo/blob/master/cc/bootloader.lisp)***. 
it uses extremely similar concepts to lllm to write Assembly, that was independently developped for a Lisp operating system called [Yalo](https://github.com/whily/yalo); I did not know of it when I came up with lllm, but I find it amazing someone else thought of combining Assembly and Lisp too.)*
## Dependencies

* [Janet](https://janet-lang.org/), as the client- and server- lisp.
* [NASM](https://www.nasm.us/), as the default backend compiler
* [JPM](https://janet-lang.org/docs/jpm.html) if you're planning to install lllm, though you could manually move the project's files around your filesystem.

## Installation

### Building from source
#### Manually
The REAL (unless declared INTEGER) and official way.
```
git clone "https://notabug.org/debris/lllm-janet"
cd lllm-janet 
jpm build
jpm test
doas(sudo) jpm install
```
##### setup.sh
Alternatively, the setup.sh script should probably do most of the job itself:
```
git clone "https://notabug.org/debris/lllm-janet"
cd lllm-janet && sh setup.sh
```
No warranty, though!
#### Via JPM
Alternatively:
```
doas(sudo) jpm install "https://notabug.org/debris/lllm-janet"
```

## Usage
The name of the executable is `lllma` , which stands for LLLM Assembler. Name may change in the future (`lljm` ?)

### Symbols in janet

There are plenty of symbols provided as `llllm`s (Libraries for LLLM). For development under [x86_64](https://wl.vern.cc/wiki/X86-64) Linux, use `lllm/llllnx`. For barebones [x86_64](https://wl.vern.cc/wiki/X86-64) development, use `lllm/lllb`.

### Documentation
This section is not complete.



Use `(doc symbol)` in the Janet REPL after importing a llllm (`(import lllm/llllnx)` for example) for the meantime.

An `lllm-operation` (**in lllm-janet**) is data of this kind:

`['operationA 'argA1 ... 'argn]`

such that `operationA` is a symbol that is equivalent to an assembly operation, `argA1` is a argument to that operation, etc...

It will be converted to assembly as the line `operationA argA1, ..., argn`.

lllm will transemble data of this kind:
```
@[
lllm-operation
...
lllm-operation
]
```
(ie. an array of `lllm-operation`s of any length.)

As such, any function or macro that generates a valid `lllm-operation` can be used to generate and abstract assembly away. This is where the power of lllm resides.

Inserting an indexable data structure like `["string"]` into an indexable to transemble will escape "string" into assembly code. This is your escape hatch. It's useful for defining odd macros like "$-$$" (though you could use a prefix-infix converter to write `(- '$ '$$)` or something).

Also, you'll probably need some x86_64 opcodes cheat sheet [like this one](https://www.felixcloutier.com/x86/) , and [maybe another](http://www.cheat-sheets.org/saved-copy/Linux_Syscall_quickref.pdf) for Linux syscalls.

And maybe a [guide](https://web.stanford.edu/class/cs107/guide/x86-64.html) on x86_64 too.

For OS development and `lllm/lllb`, or just a really good introduction to assembly, check out this great [tutorial by Daedalus Community](https://yt.beparanoid.de/playlist?list=PLm3B56ql_akNcvH8vvJRYOc7TbYhRs19M).
## Contributing
I have no idea how repository management works. If you want to contribute, please contact me through [the community space](https://matrix.to/#/#lllm:matrix.org) or [directly](https://matrix.to/#/@vertices:matrix.org) on Matrix.
### Community and support et cetera
We have a space on Matrix [here](https://matrix.to/#/#lllm:matrix.org), feel free to join.